package org.amphiprion.kidcalendar.dao.xml;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.amphiprion.kidcalendar.entity.Configuration;
import org.amphiprion.kidcalendar.entity.DateRule;
import org.amphiprion.kidcalendar.entity.Kid;
import org.amphiprion.kidcalendar.entity.Rule;
import org.amphiprion.kidcalendar.entity.RuleGroup;
import org.amphiprion.kidcalendar.entity.Vacation;
import org.amphiprion.kidcalendar.entity.VacationCalendar;
import org.amphiprion.kidcalendar.entity.VacationRule;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import android.os.Environment;

public class ConfigurationDao extends AbstractXmlDao {
	private static ConfigurationDao instance;

	public static ConfigurationDao getInstance() {
		if (instance == null) {
			instance = new ConfigurationDao();
		}
		return instance;
	}

	public Configuration getConfiguration() {
		InputStream is = null;
		try {
			Configuration configuration = new Configuration();
			String filename = Environment.getExternalStorageDirectory() + "/Amphiprion/WhoHaveTheKids/config.xml";
			if (!new File(filename).exists()) {
				File file = new File(filename);
				file.getParentFile().mkdirs();
				is = ConfigurationDao.class.getResourceAsStream("/config.xml");
				FileOutputStream fos = new FileOutputStream(file);
				int r;
				while ((r = is.read()) >= 0) {
					fos.write(r);
				}
				is.close();
				fos.close();
			}
			is = new FileInputStream(filename);
			//
			// File f = new File(filename);
			//
			// if (f.exists()) {
			// is = new FileInputStream(f);
			// }
			// if (is == null) {
			// throw new RuntimeException("File " + f.getAbsolutePath() + " does not exist!");
			// }

			DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
			builderFactory.setNamespaceAware(true);

			DocumentBuilder builder = builderFactory.newDocumentBuilder();
			Document document = builder.parse(is);

			// /////////////////////// VACATION
			ArrayList<VacationCalendar> vacationCalendars = new ArrayList<VacationCalendar>();
			configuration.setVacationCalendars(vacationCalendars);
			NodeList vacationCalendarList = ((Element) document.getElementsByTagName("vacation-calendars").item(0)).getElementsByTagName("vacation-calendar");
			for (int i = 0; i < vacationCalendarList.getLength(); i++) {
				Element vacationCalendarNode = (Element) vacationCalendarList.item(i);
				VacationCalendar vc = new VacationCalendar();
				vc.setId(getAttribute(vacationCalendarNode, "id", ""));
				vc.setName(getAttribute(vacationCalendarNode, "name", ""));
				vacationCalendars.add(vc);
				collectVacation(vacationCalendarNode, vc);
			}
			// /////////////////////// RULE GROUP
			ArrayList<RuleGroup> ruleGroups = new ArrayList<RuleGroup>();
			configuration.setRuleGroups(ruleGroups);
			NodeList ruleGroupsList = ((Element) document.getElementsByTagName("rule-groups").item(0)).getElementsByTagName("rule-group");
			for (int i = 0; i < ruleGroupsList.getLength(); i++) {
				Element ruleGroupNode = (Element) ruleGroupsList.item(i);
				RuleGroup rg = new RuleGroup();
				rg.setId(getAttribute(ruleGroupNode, "id", ""));
				rg.setName(getAttribute(ruleGroupNode, "name", ""));
				ruleGroups.add(rg);

				collectRules(configuration, ruleGroupNode, rg.getRules());
			}

			// /////////////////////// KIDS
			ArrayList<Kid> kids = new ArrayList<Kid>();
			configuration.setKids(kids);
			NodeList list = document.getElementsByTagName("kid");
			for (int i = 0; i < list.getLength(); i++) {
				Element kidNode = (Element) list.item(i);
				Kid kid = new Kid();
				kid.setName(getAttribute(kidNode, "name", ""));
				kid.setRuleGroup(configuration.getRuleGroup(getAttribute(kidNode, "rule-group-id", "")));
				kids.add(kid);
			}

			is.close();

			return configuration;
		} catch (Throwable e) {
			e.printStackTrace();
			// Log.e(ApplicationConstants.PACKAGE, "", e);
			if (is != null) {
				try {
					is.close();
				} catch (Throwable ex) {
				}
			}
			return null;
		}

	}

	private void collectVacation(Element vacationCalendarNode, VacationCalendar vc) {
		NodeList list = vacationCalendarNode.getElementsByTagName("vacation");
		for (int i = 0; i < list.getLength(); i++) {
			Element node = (Element) list.item(i);
			Vacation v = new Vacation();
			v.setName(getAttribute(node, "name", ""));
			v.setFrom(getAttribute(node, "from", ""));
			v.setTo(getAttribute(node, "to", ""));
			vc.getVacations().add(v);
		}
	}

	private void collectRules(Configuration configuration, Element parentNode, List<Rule> rules) {
		NodeList childNodes = parentNode.getChildNodes();
		for (int i = 0; i < childNodes.getLength(); i++) {
			Node node = childNodes.item(i);
			if (node.getNodeName().equals("date-rule")) {
				Element dateRuleNode = (Element) node;
				DateRule dr = new DateRule();
				dr.setType(getAttribute(dateRuleNode, "type", ""));
				dr.setValue(getAttribute(dateRuleNode, "value", ""));
				dr.setStart(getAttribute(dateRuleNode, "start", ""));
				rules.add(dr);
				collectRules(configuration, dateRuleNode, dr.getSubRules());
			} else if (node.getNodeName().equals("vacation-rule")) {
				Element vacationRuleNode = (Element) node;
				VacationRule vr = new VacationRule();
				vr.setType(getAttribute(vacationRuleNode, "type", ""));
				vr.setVacationCalendar(configuration.getVacationCalendar(getAttribute(vacationRuleNode, "vacation-calendar-id", "")));
				rules.add(vr);
				collectRules(configuration, vacationRuleNode, vr.getSubRules());
			}
		}
	}
}
